/**
 *
 */
package commons.beancopier.mapper;

import java.beans.PropertyDescriptor;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ClassUtils;

/**
 * @author 陌铭(Phenix Huang)
 *
 */
public final class BeanMapperUtils {

    /**
     * extract the property of class to be a map. If the property is not readable, it will be ignored.
     * @param cls
     * @return
     */
    public static final Map<String, String> getPropertyNameMap(Class<?> cls) {
        Map<String, String> properties = new HashMap<String, String>() ;
        PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(cls);
        for (PropertyDescriptor descriptor : descriptors) {
            if (descriptor.getReadMethod() != null) {
                if (descriptor.getWriteMethod() != null || descriptor.getPropertyType().isArray()
                        || isJavaCollectionClass(descriptor.getPropertyType())) {
                    properties.put(descriptor.getName(), descriptor.getName());
                }
            }
        }
        return properties ;
    }

    public static final boolean isJavaCollectionClass(Class<?> clz) {
        return ClassUtils.isAssignable(clz, Collection.class) || ClassUtils.isAssignable(clz, Map.class);
    }

    /**
     * base on the mapper to filter the input map.
     * @param names
     * @param mapper
     */
    public static final void filterProperties(Map<String, String> names, PropertiesMapper mapper) {
        Collection<String> needToRemove = Collections.emptyList();
        if (mapper.useExcludeList()) {
            needToRemove = mapper.getFilterPropertyNames() ;
        } else {
            Map<String, String> mapped = mapper.getMappedPropertyNames();
            if (MapUtils.isEmpty(mapped)) {
                mapped = Collections.emptyMap();
            }
            needToRemove = CollectionUtils.subtract(names.keySet(), mapped.keySet());
        }
        for (String name : needToRemove) {
            names.remove(name);
        }
    }

}
